/*-+-*****************************************************************************
 Copyright (C) 2009-2012 Oceanside Software Corporation (R)
 Dallas, Texas

 Author       : Jason T. Brower
 Purpose      : This file is part of a point-of-sale software package
                originally written for Table-Service Restaurants.
              
 Date         : July 8th of 2012
              
 History      : The application that this software file belongs to was 
                written over a 3-Year period.  The first version was written
                in C# .Net 3.5 using Windows Forms.  Being new to .Net at
                the time, I soon learned of Windows Presentation Foundation,
                liked the graphics capabilities and databinding so I
                migrated to WPF.  When the .Net 4.0 framework was released
                the application was migrated from 3.5 to 4.0. Now today,
                .Net 4.5 RC is out and I was already in process of migrating
                before I made this public.
                
Excuse Me     : Please excuse the coding style, it is not representative of
                my typical work.  During the three years I was under a very
                tight budget, constantly running out of funding and was 
                working 18 hour days hyped up on 5-Hour Energy.  The 
                design is not textbook.  It is monolythic because of
                previous issues I will not get into.  There are few comments
                in the code and the ones that are there may be incorrect.
                
What it is not: This is not the exact version that I took through PA-DSS 2.0
                nor is it the exact version running at my customer sites.
                I removed some details for security purposes including some
                encryption algorithms.  The reporting was removed because
                I was including a third party library that cannot be 
                published with this Open Source.
                
What it is    : This application has been running at high volume restaraunts
                for over a year.  It never freezes, crashes or does anything
                unexpected.  So long as it is built, installed and configured
                correctly, it is a strong system that we can all enhance.

Contact       : Please note that I can no longer work for free.  However, you
                can reach me at information@oceansidesw.com.                                                      

*********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Oceanside.Payments.Prepaid;
using Oceanside.Payments;
using System.Data.Objects;
#if _LOCALDB
  using Oceanside.LocalDB;
#else
using Oceanside.RemoteDB;
#endif

#if _LOCALDB
  namespace Oceanside.LocalDB
#else
namespace Oceanside.RemoteDB
#endif
{
    public partial class SALE
    {
        public enum ENUM_TAXRATE_TYPE
        {
            EXLUSIVE,
            INCLUSIVE
        }

        private int whenToManageItemNumber = 0;
        public int WhenToManageItemNumber
        {
            get { return whenToManageItemNumber; }
            set { whenToManageItemNumber = value; }
        }

        internal class ProcessPrepaidRequest
        {
            public AskForCCMessageBox AskForCCMessageBox;
            public PRODUCT_GROUP SelectedProductGroup;
            public PRODUCT SelectedProduct;
            public int SelectedSeatIndex;
            public bool IsForcedProduct;
            public SALE Sale;
            public GIFT_CARDS_SOLD Gcs;
        }

        private static ProcessPrepaidRequest _currentPrepaidRequest = null;
        internal static ProcessPrepaidRequest CurrentPrepaidRequest
        {
            get { return SALE._currentPrepaidRequest; }
            set { SALE._currentPrepaidRequest = value; }
        }

        public static SALE AddProductSale(
            PRODUCT_GROUP _selectedProductGroup,
            PRODUCT _selectedProduct,
            int _selectedSeatIndex,
            bool isForcedProduct)
        {
            GIFT_CARDS_SOLD gcs = null;
            SALE sale = new SALE();
            sale.DaypartId = DAYPART.GetCurrDaypart(SHIFT.GlobalContext).Id;
            sale.RevenueCenterId = KIOSK.Get(SHIFT.GlobalContext).RevenueCenterId;

            if (_selectedProduct.PromptForPrice)
            {
                App.CashMoneyWindowInstance.ShowMe(25.00M, CashMoneyBox.CashBoxType.TYPE_PAYMENT);
                if (CashMoneyBox.LastResponse == UserResponse.ENTER)
                {
                    sale.ActualPrice = CashMoneyBox.TotalAmount;
                    sale.MenuPrice = CashMoneyBox.TotalAmount;
                }
            }

            if (_selectedProduct.IsGiftCard)
            {
                gcs = new GIFT_CARDS_SOLD();
                gcs.Amount = sale.ActualPrice;
                gcs.DateStamp = DateTime.Now;
                gcs.DaypartId = sale.DaypartId;
                gcs.RevenueCenterId = sale.RevenueCenterId;
                gcs.ORDER = SHIFT.SelectedOrder;
                sale.IsGiftCardSale = true;
                _currentPrepaidRequest = new ProcessPrepaidRequest();
                _currentPrepaidRequest.AskForCCMessageBox =
                    new AskForCCMessageBox("Please swipe the gift card you are selling or press the [X] to cancel.");
                _currentPrepaidRequest.Gcs = gcs;
                _currentPrepaidRequest.IsForcedProduct = isForcedProduct;
                _currentPrepaidRequest.Sale = sale;
                _currentPrepaidRequest.SelectedProduct = _selectedProduct;
                _currentPrepaidRequest.SelectedProductGroup = _selectedProductGroup;
                _currentPrepaidRequest.SelectedSeatIndex = _selectedSeatIndex;

                _currentPrepaidRequest.AskForCCMessageBox.ShowDialog();
                if (AskForCCMessageBox.LastUserResponse == UserResponse.EXIT)
                {
                    sale = null;
                    gcs = null;
                    _currentPrepaidRequest = null;
                }
                return null;
            }
            else
            {
                return FinishAddingProductSale(_selectedProductGroup, _selectedProduct, _selectedSeatIndex, isForcedProduct, sale, null);
            }
        }

        private static SALE FinishAddingProductSale(
            PRODUCT_GROUP _selectedProductGroup,
            PRODUCT _selectedProduct,
            int _selectedSeatIndex,
            bool isForcedProduct,
            SALE sale,
            GIFT_CARDS_SOLD gcs)
        {
            AUTO_GRATUITY currentAutoGratuity = KIOSK.GetActiveAutoGratuity(SHIFT.SelectedOrder.GuestCount);
            REVENUE_TYPE rt = SHIFT.GlobalContext.REVENUE_TYPES.Where(r => r.Id == _selectedProduct.RevenueTypeId).FirstOrDefault();

            sale.RevenueTypeId = _selectedProduct.RevenueTypeId;
            sale.CountOrdered = 1;
            sale.CountPendingKitchenSend = 1;
            sale.CountsAsSalesRevenue = rt != null ? rt.IncludedInNetSales : true;
            sale.IsExceptionModifier = false;
            sale.IsForcedModifier = false;
            sale.MenuPrice = _selectedProduct.Price;
            sale.OnHold = false;
            sale.FirstOrderedDateTime = DateTime.Now;
            sale.LastOrderedDateTime = sale.FirstOrderedDateTime;
            if (Constants.IsQuickServiceMode)
            {
                sale.OwningSeatNumber = 0;
            }
            else
            {
                sale.OwningSeatNumber = _selectedSeatIndex;
            }

            if (SHIFT.SelectedOrder.SplitBySeatHasBeenApplied == true)
            {
                sale.OwningCheckNumber = _selectedSeatIndex;

                if (_selectedSeatIndex >= SHIFT.SelectedOrder.CheckCount)
                {
                    SHIFT.SelectedOrder.CheckCount++;
                }
            }
            else
            {
                sale.OwningCheckNumber = 0;
            }
            sale.PrinterGroupingId = _selectedProduct.ProductGroupPrinterId;
            sale.ProductId = _selectedProduct.Id;
            sale.ProductIsDiscountable = _selectedProductGroup.CanDiscountGroup;
            sale.ProductName = _selectedProduct.Name;
            sale.ProductsMainCatId = _selectedProductGroup.Id;
            sale.Sku = _selectedProduct.SKU;
            sale.UserId = SHIFT.Current.User.Id;
            sale.WasVoided = false;
            sale.ORDER = SHIFT.SelectedOrder;
            sale.BumpbarPreparedTimed = DateTime.Now;
            sale.IsForcedProduct = isForcedProduct;


            if (!_selectedProduct.PromptForPrice)
            {
                decimal calculatedPrice = _selectedProduct.Price;
                if (_selectedProductGroup.ApplyGroupPrice)
                {
                    calculatedPrice = _selectedProductGroup.GroupPrice;
                    sale.MenuPrice = _selectedProductGroup.GroupPrice;
                }

                PRICE_INTERVAL_DISCOUNT priceIntervalDiscount = _selectedProductGroup.GetCurrentPriceIntervalDiscount();
                if (priceIntervalDiscount != null)
                {
                    if (priceIntervalDiscount.IsDollarsOff)
                    {
                        calculatedPrice -= priceIntervalDiscount.AmountOrPercent;
                    }
                    else if (priceIntervalDiscount.IsSpecifiedPrice)
                    {
                        calculatedPrice = priceIntervalDiscount.AmountOrPercent;
                    }
                    else if (priceIntervalDiscount.IsPercentOff)
                    {
                        calculatedPrice = calculatedPrice - (calculatedPrice * (priceIntervalDiscount.AmountOrPercent / 100M));
                        calculatedPrice = Math.Round(calculatedPrice, 2, MidpointRounding.AwayFromZero);
                    }
                }
                if (calculatedPrice < 0)
                {
                    calculatedPrice = 0;
                }

                if (currentAutoGratuity != null)
                {
                    sale.AutoGratuityId = currentAutoGratuity.Id;
                    sale.AutoGratuityRate = (currentAutoGratuity.AutoGratuityRate / 100M);
                    sale.ApplyAutoGratToMenuPrice = currentAutoGratuity.ApplyOnMenuPrice;
                }

                sale.ActualPrice = calculatedPrice;
            }
            ///Apply the exclusive tax if there is one.
            if (_selectedProduct.ExclusiveTaxRateId != 0)
            {
                EXCLUSIVE_TAXRATE rate = SHIFT.GlobalContext.EXCLUSIVE_TAXRATES.
                    Where(s => s.Id == _selectedProduct.ExclusiveTaxRateId).FirstOrDefault();

                if (rate != null)
                {
                    sale.ExclusiveTaxRate = (rate.Rate / 100M);
                    sale.ExclusiveTaxRateId = rate.Id;
                }
            }
            ///Apply the inclusive tax if there is one.
            if (_selectedProduct.InclusiveTaxRateId != null)
            {
                INCLUSIVE_TAXRATE rate = SHIFT.GlobalContext.INCLUSIVE_TAXRATES.
                    Where(s => s.Id == _selectedProduct.InclusiveTaxRateId).FirstOrDefault();

                if (rate != null)
                {
                    sale.InclusiveTaxRate = (rate.Rate / 100M);
                    sale.InclusiveTaxRateId = rate.Id;
                }
            }
            if (_selectedProduct.SurchargeId != null)
            {
                SURCHARGE_ACCOUNT rate = SHIFT.GlobalContext.SURCHARGE_ACCOUNTS.
                    Where(s => s.Id == _selectedProduct.SurchargeId).FirstOrDefault();

                if (rate != null)
                {
                    if (rate.IsFlatFee)
                    {
                        sale.SurchargeAmountFlatFee = rate.Rate;
                    }
                    else
                    {
                        sale.SurchargeRate = (rate.Rate / 100M);
                    }
                    sale.SurchargeId = rate.Id;
                    sale.SurchargeManagerId = SHIFT.Current.User.Id;
                }
            }

            sale.SeatSequenceNumber = SHIFT.SelectedOrder.GetSeatsSales(sale.OwningSeatNumber).Count();
            sale.CheckSequenceNumber = SHIFT.SelectedOrder.GetChecksSales(sale.OwningCheckNumber).Count();

            SHIFT.SelectedOrder.SALES.Add(sale);

            if (_selectedProduct.IsGiftCard && gcs != null)
            {
                SHIFT.GlobalContext.SaveChanges();
                gcs.SaleId = sale.Id;
                SHIFT.SelectedOrder.GIFT_CARDS_SOLDS.Add(gcs);
            }

            return sale;
        }


        public static SALE AddForcedModSale(
            FORCED_MODIFIER_GROUP parentForcedModGroup,
            FORCED_MODIFIER relatedSelectedForcedModifier,
            SALE parentSale,
            int owningSeatNumber,
            bool productIsCompable)
        {
            AUTO_GRATUITY currentAutoGratuity = KIOSK.GetActiveAutoGratuity(SHIFT.SelectedOrder.GuestCount);
            REVENUE_TYPE rt =
                SHIFT.GlobalContext.REVENUE_TYPES.Where(r => r.Id == relatedSelectedForcedModifier.RevenueTypeId).FirstOrDefault();

            ///Create a new sale for the modifier.
            SALE sale = new SALE();
            sale.RevenueTypeId = relatedSelectedForcedModifier.RevenueTypeId;
            sale.CountOrdered = 1;
            sale.CountPendingKitchenSend = 1;
            sale.CountsAsSalesRevenue = rt != null ? rt.IncludedInNetSales : true;
            sale.DaypartId = DAYPART.GetCurrDaypart(SHIFT.GlobalContext).Id;
            sale.IsExceptionModifier = false;
            sale.IsForcedModifier = true;
            sale.MenuPrice = relatedSelectedForcedModifier.Price;
            sale.ActualPrice = relatedSelectedForcedModifier.Price;
            sale.OnHold = false;
            sale.FirstOrderedDateTime = DateTime.Now;
            sale.LastOrderedDateTime = sale.FirstOrderedDateTime;
            if (Constants.IsQuickServiceMode)
            {
                sale.OwningSeatNumber = 0;
            }
            else
            {
                sale.OwningSeatNumber = owningSeatNumber;
            }
            sale.PARENTSALE_WHEN_MODSALE = parentSale;
            sale.PrinterGroupingId = relatedSelectedForcedModifier.ProductGroupPrinterId;
            sale.ProductId = relatedSelectedForcedModifier.Id;
            sale.ProductIsDiscountable = productIsCompable;
            sale.ProductName = relatedSelectedForcedModifier.Name;
            sale.ProductsMainCatId = parentForcedModGroup.Id;
            sale.RevenueCenterId = KIOSK.Get(SHIFT.GlobalContext).RevenueCenterId;
            sale.Sku = relatedSelectedForcedModifier.SKU;
            sale.UserId = SHIFT.Current.User.Id;
            sale.WasVoided = false;
            sale.ORDER = SHIFT.SelectedOrder;
            sale.OwningCheckNumber = parentSale.OwningCheckNumber;
            sale.BumpbarPreparedTimed = DateTime.Now;

            if (parentForcedModGroup.ApplyGroupPrice)
            {
                sale.ActualPrice = parentForcedModGroup.GroupPrice;
                sale.MenuPrice = parentForcedModGroup.GroupPrice;
            }


            if (currentAutoGratuity != null)
            {
                sale.AutoGratuityId = currentAutoGratuity.Id;
                sale.AutoGratuityRate = (currentAutoGratuity.AutoGratuityRate / 100M);
                sale.ApplyAutoGratToMenuPrice = currentAutoGratuity.ApplyOnMenuPrice;
            }


            ///Apply the exclusive tax if there is one.
            if (relatedSelectedForcedModifier.ExclusiveTaxRateId != 0)
            {
                EXCLUSIVE_TAXRATE rate = SHIFT.GlobalContext.EXCLUSIVE_TAXRATES.
                    Where(s => s.Id == relatedSelectedForcedModifier.ExclusiveTaxRateId).FirstOrDefault();

                if (rate != null)
                {
                    sale.ExclusiveTaxRate = (rate.Rate / 100M);
                    sale.ExclusiveTaxRateId = rate.Id;
                }
            }
            ///Apply the inclusive tax if there is one.
            if (relatedSelectedForcedModifier.InclusiveTaxRateId != null)
            {
                INCLUSIVE_TAXRATE rate = SHIFT.GlobalContext.INCLUSIVE_TAXRATES.
                    Where(s => s.Id == relatedSelectedForcedModifier.InclusiveTaxRateId).FirstOrDefault();

                if (rate != null)
                {
                    sale.InclusiveTaxRate = (rate.Rate / 100M);
                    sale.InclusiveTaxRateId = rate.Id;
                }
            }
            if (relatedSelectedForcedModifier.SurchargeId != null)
            {
                SURCHARGE_ACCOUNT rate = SHIFT.GlobalContext.SURCHARGE_ACCOUNTS.
                    Where(s => s.Id == relatedSelectedForcedModifier.SurchargeId).FirstOrDefault();

                if (rate != null)
                {
                    if (rate.IsFlatFee)
                    {
                        sale.SurchargeAmountFlatFee = rate.Rate;
                    }
                    else
                    {
                        sale.SurchargeRate = (rate.Rate / 100M);
                    }
                    sale.SurchargeId = rate.Id;
                    sale.SurchargeManagerId = SHIFT.Current.User.Id;
                }
            }

            sale.SeatSequenceNumber = SHIFT.SelectedOrder.GetSeatsSales(sale.OwningSeatNumber).Count();
            sale.CheckSequenceNumber = SHIFT.SelectedOrder.GetChecksSales(sale.OwningCheckNumber).Count();
            SHIFT.SelectedOrder.SALES.Add(sale);
            return sale;
        }

        public static SALE AddExceptionModSale(
            EXCEPTION_MODIFIER_GROUP parentExceptionModGroup,
            EXCEPTION_MODIFIER relatedSelectedExceptionModifier,
            SALE parentSale,
            int owningSeatNumber,
            bool productIsCompable)
        {
            AUTO_GRATUITY currentAutoGratuity = KIOSK.GetActiveAutoGratuity(SHIFT.SelectedOrder.GuestCount);
            REVENUE_TYPE rt =
                SHIFT.GlobalContext.REVENUE_TYPES.Where(r => r.Id == relatedSelectedExceptionModifier.RevenueTypeId).FirstOrDefault();

            ///Create a new sale for the modifier.
            SALE sale = new SALE();
            sale.RevenueTypeId = relatedSelectedExceptionModifier.RevenueTypeId;
            sale.CountOrdered = 1;
            sale.CountPendingKitchenSend = 1;
            sale.CountsAsSalesRevenue = rt != null ? rt.IncludedInNetSales : true;
            sale.DaypartId = DAYPART.GetCurrDaypart(SHIFT.GlobalContext).Id;
            sale.IsExceptionModifier = true;
            sale.IsForcedModifier = false;
            sale.MenuPrice = relatedSelectedExceptionModifier.Price;
            sale.ActualPrice = relatedSelectedExceptionModifier.Price;
            sale.OnHold = false;
            sale.FirstOrderedDateTime = DateTime.Now;
            sale.LastOrderedDateTime = sale.FirstOrderedDateTime;
            sale.BumpbarPreparedTimed = sale.FirstOrderedDateTime;

            if (Constants.IsQuickServiceMode)
            {
                sale.OwningSeatNumber = 0;
            }
            else
            {
                sale.OwningSeatNumber = owningSeatNumber;
            }
            sale.OwningCheckNumber = parentSale.OwningCheckNumber;
            sale.PARENTSALE_WHEN_MODSALE = parentSale;
            sale.PrinterGroupingId = parentSale.PrinterGroupingId;
            sale.ProductId = relatedSelectedExceptionModifier.Id;
            sale.ProductIsDiscountable = productIsCompable;
            sale.ProductName = relatedSelectedExceptionModifier.Name;
            sale.ProductsMainCatId = parentExceptionModGroup.Id;
            sale.RevenueCenterId = KIOSK.Get(SHIFT.GlobalContext).RevenueCenterId;
            sale.Sku = relatedSelectedExceptionModifier.SKU;
            sale.UserId = SHIFT.Current.User.Id;
            sale.WasVoided = false;

            if (parentExceptionModGroup.ApplyGroupPrice)
            {
                sale.ActualPrice = parentExceptionModGroup.GroupPrice;
                sale.MenuPrice = parentExceptionModGroup.GroupPrice;
            }


            if (currentAutoGratuity != null)
            {
                sale.AutoGratuityId = currentAutoGratuity.Id;
                sale.AutoGratuityRate = (currentAutoGratuity.AutoGratuityRate / 100M);
                sale.ApplyAutoGratToMenuPrice = currentAutoGratuity.ApplyOnMenuPrice;
            }


            ///Apply the exclusive tax if there is one.
            if (relatedSelectedExceptionModifier.ExclusiveTaxRateId != 0)
            {
                EXCLUSIVE_TAXRATE rate = SHIFT.GlobalContext.EXCLUSIVE_TAXRATES.
                    Where(s => s.Id == relatedSelectedExceptionModifier.ExclusiveTaxRateId).FirstOrDefault();

                if (rate != null)
                {
                    sale.ExclusiveTaxRate = (rate.Rate / 100M);
                    sale.ExclusiveTaxRateId = rate.Id;
                }
            }
            ///Apply the inclusive tax if there is one.
            if (relatedSelectedExceptionModifier.InclusiveTaxRateId != null)
            {
                INCLUSIVE_TAXRATE rate = SHIFT.GlobalContext.INCLUSIVE_TAXRATES.
                    Where(s => s.Id == relatedSelectedExceptionModifier.InclusiveTaxRateId).FirstOrDefault();

                if (rate != null)
                {
                    sale.InclusiveTaxRate = (rate.Rate / 100M);
                    sale.InclusiveTaxRateId = rate.Id;
                }
            }
            if (relatedSelectedExceptionModifier.SurchargeId != null)
            {
                SURCHARGE_ACCOUNT rate = SHIFT.GlobalContext.SURCHARGE_ACCOUNTS.
                    Where(s => s.Id == relatedSelectedExceptionModifier.SurchargeId).FirstOrDefault();

                if (rate != null)
                {
                    if (rate.IsFlatFee)
                    {
                        sale.SurchargeAmountFlatFee = rate.Rate;
                    }
                    else
                    {
                        sale.SurchargeRate = (rate.Rate / 100M);
                    }
                    sale.SurchargeId = rate.Id;
                    sale.SurchargeManagerId = SHIFT.Current.User.Id;
                }
            }

            SALE.InsertNewSeatSequenceSale(sale, parentSale.SeatSequenceNumber + 1, owningSeatNumber);
            SALE.InsertNewCheckSequenceSale(sale, parentSale.CheckSequenceNumber + 1, parentSale.OwningCheckNumber);

            sale.ORDER = SHIFT.SelectedOrder;
            SHIFT.SelectedOrder.SALES.Add(sale);
            return sale;
        }

        public static SALE SeparateSale(SALE likeSale, bool isCheck, int howMany)
        {
            likeSale.CountOrdered -= howMany;

            SALE newSale = new SALE();
            newSale._RevenueTypeId = likeSale.RevenueTypeId;
            newSale._ActualPrice = likeSale.ActualPrice;
            newSale._AutoGratuityId = likeSale._AutoGratuityId;
            newSale._AutoGratuityRate = likeSale._AutoGratuityRate;
            newSale._BumpbarPreparedTimed = likeSale._BumpbarPreparedTimed;
            //newSale._CheckSequenceNumber = likeSale._CheckSequenceNumber;
            newSale._DiscountRate = likeSale._DiscountRate;
            newSale._DiscountId = likeSale._DiscountId;
            newSale._DiscountManagerId = likeSale._DiscountManagerId;
            newSale._CountOrdered = HowManyBox.LastNumberSelection;
            newSale._CountPendingKitchenSend = 0;
            newSale._CountsAsSalesRevenue = likeSale.CountsAsSalesRevenue;
            newSale._DaypartId = likeSale._DaypartId;
            newSale._ExclusiveTaxRate = likeSale._ExclusiveTaxRate;
            newSale._ExclusiveTaxRateId = likeSale._ExclusiveTaxRateId;
            newSale._FirstOrderedDateTime = likeSale._FirstOrderedDateTime;
            newSale._InclusiveTaxRate = likeSale._InclusiveTaxRate;
            newSale._InclusiveTaxRateId = likeSale._InclusiveTaxRateId;
            newSale._IsExceptionModifier = likeSale._IsExceptionModifier;
            newSale._IsForcedModifier = likeSale._IsForcedModifier;
            newSale._IsForcedProduct = likeSale._IsForcedProduct;
            newSale._IsWithout = likeSale._IsWithout;
            newSale._LastOrderedDateTime = likeSale._LastOrderedDateTime;
            newSale._MenuPrice = likeSale._MenuPrice;
            newSale._NavOrderId = likeSale._NavOrderId;
            newSale._NavParentSaleWhenModSaleId = likeSale._NavParentSaleWhenModSaleId;
            newSale._NoteForPrint = likeSale._NoteForPrint;
            newSale._NoteForPrintBeforeHold = likeSale._NoteForPrintBeforeHold;
            newSale._Notes = likeSale._Notes;
            newSale._OnHold = likeSale._OnHold;
            newSale._Ordermode = likeSale._Ordermode;
            newSale._OwningCheckNumber = likeSale._OwningCheckNumber;
            newSale._OwningSeatNumber = likeSale._OwningSeatNumber;
            newSale._PrinterGroupingId = likeSale._PrinterGroupingId;
            newSale._PrintJobId = likeSale._PrintJobId;
            newSale._ProductId = likeSale._ProductId;
            newSale._ProductIsDiscountable = likeSale._ProductIsDiscountable;
            newSale._ProductName = likeSale._ProductName;
            newSale._ProductsMainCatId = likeSale._ProductsMainCatId;
            newSale._RevenueCenterId = likeSale._RevenueCenterId;
            newSale._SeatSequenceNumber = likeSale._SeatSequenceNumber;
            newSale._Sku = likeSale._Sku;
            newSale._SurchargeRate = likeSale._SurchargeRate;
            newSale._SurchargeId = likeSale._SurchargeId;
            newSale._SurchargeManagerId = likeSale._SurchargeManagerId;
            newSale._SurchargeAmountFlatFee = likeSale._SurchargeAmountFlatFee;
            newSale._UserId = likeSale._UserId;
            newSale._WasCompedInEntire = likeSale._WasCompedInEntire;
            newSale._WasVoided = likeSale._WasVoided;

            if (isCheck)
            {
                SALE.InsertNewCheckSequenceSale(
                    newSale,
                    likeSale.CheckSequenceNumber + 1,
                    likeSale.OwningCheckNumber);
            }
            else
            {
                SALE.InsertNewSeatSequenceSale(
                    newSale,
                    likeSale.SeatSequenceNumber + 1,
                    likeSale.OwningSeatNumber);
            }

            newSale.ORDER = SHIFT.SelectedOrder;
            SHIFT.SelectedOrder.SALES.Add(newSale);

            return newSale;
        }

        public static void ProcessPrepaidRequest_NOTHROW(MagneticCard magCard)
        {
            try
            {
                Constants.MainDispatcher.BeginInvoke(new Action(() => _currentPrepaidRequest.AskForCCMessageBox.Close()));
                App.InvokeStopStoryBoard_NOTHROW();

                string response;
                Payments.Prepaid.Issue data = new Payments.Prepaid.Issue();
                TRANSACTION_RESPONSE respMessage = new TRANSACTION_RESPONSE();
                data.InvoiceNo = respMessage.Id.ToString();
                data.Purchase = CurrentPrepaidRequest.Sale.ActualPrice.ToString("#0.00");
                data.IpPort = "9100";
                response = data.Request(magCard);
                respMessage.Parse(response);

                if (respMessage.CmdStatusOk)
                {
                    decimal authorize = 0M;
                    if (respMessage.Authorize != null)
                    {
                        try
                        {
                            authorize = Convert.ToDecimal(respMessage.Authorize);
                        }
                        catch (Exception e)
                        {
                            Logging.LogException(e);
                        }
                        _currentPrepaidRequest.Gcs.Amount = authorize;
                    }
                    else
                    {
                        _currentPrepaidRequest.Gcs.Amount = 0M;
                    }

                    FinishAddingProductSale(
                        CurrentPrepaidRequest.SelectedProductGroup,
                        CurrentPrepaidRequest.SelectedProduct,
                        CurrentPrepaidRequest.SelectedSeatIndex,
                        CurrentPrepaidRequest.IsForcedProduct,
                        CurrentPrepaidRequest.Sale,
                        CurrentPrepaidRequest.Gcs);

                    Constants.MainDispatcher.BeginInvoke(new Action(() => POBindings.UpdateTicketFocus(true)));
                }
                else
                {
                    if (respMessage.TextResponse != null && respMessage.TextResponse.Equals("Account Already Issued"))
                    {
                        Constants.MainDispatcher.BeginInvoke(new Action(() =>
                        {
                            YesNoBox ynb = new YesNoBox("This card has already been issued.  Would you like to add more funds to this gift card?");
                            ynb.ShowDialog();
                            if (YesNoBox.LastResponse == UserResponse.YES)
                            {
                                App.InvokeStartStoryBoard_NOTHROW();
                                System.Threading.Tasks.Task.Factory.StartNew(new Action(() =>
                                    {
                                        try
                                        {
                                            Payments.Prepaid.Reload pdata = new Payments.Prepaid.Reload();
                                            TRANSACTION_RESPONSE prespMessage = new TRANSACTION_RESPONSE();
                                            pdata.InvoiceNo = SHIFT.SelectedOrder.Id.ToString();
                                            pdata.Purchase = CurrentPrepaidRequest.Sale.ActualPrice.ToString("#0.00");
                                            pdata.IpPort = "9100";
                                            response = pdata.Request(magCard);
                                            prespMessage.Parse(response);

                                            if (prespMessage.CmdStatusOk)
                                            {
                                                decimal authorize = 0M;
                                                if (prespMessage.Authorize != null)
                                                {
                                                    try
                                                    {
                                                        authorize = Convert.ToDecimal(prespMessage.Authorize);
                                                    }
                                                    catch (Exception e)
                                                    {
                                                        Logging.LogException(e);
                                                    }
                                                    _currentPrepaidRequest.Gcs.Amount = authorize;
                                                }
                                                else
                                                {
                                                    _currentPrepaidRequest.Gcs.Amount = 0M;
                                                }

                                                FinishAddingProductSale(
                                                    CurrentPrepaidRequest.SelectedProductGroup,
                                                    CurrentPrepaidRequest.SelectedProduct,
                                                    CurrentPrepaidRequest.SelectedSeatIndex,
                                                    CurrentPrepaidRequest.IsForcedProduct,
                                                    CurrentPrepaidRequest.Sale,
                                                    CurrentPrepaidRequest.Gcs);
                                                CurrentPrepaidRequest = null;
                                                Constants.MainDispatcher.BeginInvoke(new Action(() => POBindings.UpdateTicketFocus(true)));
                                            }
                                            else
                                            {
                                                CurrentPrepaidRequest = null;
                                                UMD.ShowGuiMessageSTASafe_NOTHROW("The processor returned an error code of ["
                                                    + prespMessage.CmdStatus + "] and a message of [" + prespMessage.TextResponse + "].");
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                            CurrentPrepaidRequest = null;
                                            Logging.LogException(e);
                                        }
                                        finally
                                        {
                                            App.InvokeStopStoryBoard_NOTHROW();
                                        }
                                    }));
                            }
                        }));

                    }
                    else
                    {
                        CurrentPrepaidRequest = null;
                        UMD.ShowGuiMessageSTASafe_NOTHROW("The processor returned an error code of ["
                            + respMessage.CmdStatus + "] and a message of [" + respMessage.TextResponse + "].");
                    }
                }
            }
            catch (Exception e)
            {
                CurrentPrepaidRequest = null;
                App.InvokeStopStoryBoard_NOTHROW();
                Logging.LogException(e);
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }

        private static List<SALE> RecursiveGetModSales(List<SALE> salesList)
        {
            List<SALE> allRelatedSales = new List<SALE>(salesList);
            if (salesList.Count != 0)
            {
                foreach (SALE sale in salesList)
                {
                    List<SALE> relatedSales = RecursiveGetModSales(sale.MODSALES.ToList());
                    if (relatedSales != null)
                    {
                        foreach (SALE s in relatedSales)
                        {
                            allRelatedSales.Add(s);
                        }
                    }
                }
            }
            return allRelatedSales;
        }

        public void TryDeleteSinglePendingSale()
        {
            if (!IsForcedProduct)
            {
                if (CountPendingKitchenSend == CountOrdered && CountOrdered == 1)
                {
                    List<SALE> listOfSalesToDelete = RecursiveGetModSales(this.MODSALES.ToList());
                    listOfSalesToDelete.Add(this);

                    foreach (SALE delSal in listOfSalesToDelete)
                    {
                        delSal.MODSALES.Clear();
                        delSal.OnHold = false;
                        SHIFT.SelectedOrder.SALES.Remove(delSal);
                        SHIFT.GlobalContext.SALES.DeleteObject(delSal);
                    }

                    SHIFT.SelectedOrder.HasProductsOnHold = false;
                    foreach (SALE s in SHIFT.SelectedOrder.SALES)
                    {
                        if (s.OnHold)
                        {
                            SHIFT.SelectedOrder.HasProductsOnHold = true;
                            break;
                        }
                    }
                }
                else if (CountPendingKitchenSend > 0)
                {
                    CountOrdered--;
                    CountPendingKitchenSend--;
                }
            }
        }

        public void TryDeleteAllCountPendingSale()
        {
            if (!IsForcedProduct)
            {
                if (CountPendingKitchenSend == CountOrdered)
                {
                    List<SALE> listOfSalesToDelete = RecursiveGetModSales(this.MODSALES.ToList());
                    listOfSalesToDelete.Add(this);

                    foreach (SALE delSal in listOfSalesToDelete)
                    {
                        delSal.MODSALES.Clear();
                        SHIFT.SelectedOrder.SALES.Remove(delSal);
                        SHIFT.GlobalContext.SALES.DeleteObject(delSal);
                    }
                }
                else if (CountPendingKitchenSend > 0)
                {
                    CountOrdered -= CountPendingKitchenSend;
                    CountPendingKitchenSend = 0;
                }
            }
        }

        public static void InsertNewSeatSequenceSale(SALE newSale, int position, int seat)
        {
            newSale.SeatSequenceNumber = position;
            List<SALE> seatsSales = SHIFT.SelectedOrder.GetSeatsSales(seat).ToList();
            for (int i = position - 1; i < seatsSales.Count; i++)
            {
                seatsSales[i].SeatSequenceNumber = i + 2;
            }
        }

        public static void InsertNewCheckSequenceSale(SALE newSale, int position, int check)
        {
            newSale.CheckSequenceNumber = position;
            List<SALE> checkSales = SHIFT.SelectedOrder.GetChecksSales(check).ToList();
            for (int i = position - 1; i < checkSales.Count; i++)
            {
                checkSales[i].CheckSequenceNumber = i + 2;
            }
        }


        private enum PRICE_CALC_ENUM
        {
            EXCEPTION_PRICE,
            FORCED_PRICE,
            PRODUCT_PRICE
        }

        private static decimal GetProductsActualPrice(Int64 mainId, Int64 prodId, PRICE_CALC_ENUM type)
        {
            decimal calculatedPrice = 0M;

            PRODUCT_GROUP pg = PRODUCT_GROUP.GetProductGroupById(mainId, SHIFT.GlobalContext);
            PRODUCT prod = PRODUCT.GetProductById(prodId);
            calculatedPrice = prod.Price;

            if (pg != null && pg.ApplyGroupPrice)
            {
                calculatedPrice = pg.GroupPrice;
            }

            PRICE_INTERVAL_DISCOUNT priceIntervalDiscount = pg.GetCurrentPriceIntervalDiscount();
            if (priceIntervalDiscount != null)
            {
                if (priceIntervalDiscount.IsDollarsOff)
                {
                    calculatedPrice -= priceIntervalDiscount.AmountOrPercent;
                }
                else if (priceIntervalDiscount.IsSpecifiedPrice)
                {
                    calculatedPrice = priceIntervalDiscount.AmountOrPercent;
                }
                else if (priceIntervalDiscount.IsPercentOff)
                {
                    calculatedPrice = calculatedPrice - (calculatedPrice * (priceIntervalDiscount.AmountOrPercent / 100M));
                }
            }

            if (calculatedPrice < 0)
            {
                calculatedPrice = 0;
            }
            return calculatedPrice;
        }

        public static void GetLikeProductSale(out SALE sale,
            ORDER currOrder,
            PRODUCT selProd,
            Int64 prodGroupId,
            int selSeatIndx,
            int salesCheckIndx)
        {

            sale = null;
            try
            {
                AUTO_GRATUITY ag = KIOSK.GetActiveAutoGratuity(SHIFT.SelectedOrder.GuestCount);
                decimal price = GetProductsActualPrice(prodGroupId, selProd.Id, PRICE_CALC_ENUM.PRODUCT_PRICE);

                ///If the product already exists in the list, then we can just increase its count
                ///unless it is a modifier or has varying dicounts applied to it.
                var qSearchForLikeSales = from SL in SHIFT.SelectedOrder.SALES
                                          where SL.IsExceptionModifier == false &&
                                          SL.IsForcedModifier == false &&
                                          (SL.NoteForPrint == null || SL.NoteForPrint == "") &&
                                          SL.ProductId == selProd.Id &&
                                          (SL.ActualPrice == price) &&
                                          ((SL.AutoGratuityId == null && ag == null) ||
                                          (SL.AutoGratuityId != null && ag != null && SL.AutoGratuityId == ag.Id)) &&
                                          (SL.DiscountId == null) &&
                                          !SL.IsGiftCardSale &&
                                          SL.OwningSeatNumber == selSeatIndx &&
                                          SL.OwningCheckNumber == salesCheckIndx
                                          select SL;

                if (qSearchForLikeSales.Any())
                {
                    sale = qSearchForLikeSales.FirstOrDefault();
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
        }

        public delegate void CompByEmployeeReportCallbackType(List<CompReport> report);


        /// <summary>
        /// 
        /// </summary>
        public class CompReport
        {
            public System.Linq.IGrouping<long?, SALE> CompPayments { get; set; }
            public COMP_ACCOUNT Comp { get; set; }
            public int Count { get; set; }
            public string CountStr
            {
                get
                {
                    return Count.ToString();
                }
            }
            public decimal Sales { get; set; }
            public string UserName { get; set; }
        }

        /// <summary>
        /// 
        /// </summary>
        private class EmployeeCompInput
        {
            public DateTime StartDate { get; set; }
            public DateTime EndDate { get; set; }
            public int Take { get; set; }
            public Int64 EmployeeId { get; set; }

        }

        /// <summary>
        /// 
        /// </summary>
        private class CompExpenseReportInput
        {
            public DateTime StartDate { get; set; }
            public DateTime EndDate { get; set; }
            public Int64 CompId { get; set; }
            public Int64 UserId { get; set; }
        }

        private static readonly Func<DominicaEntities,
           EmployeeCompInput, IQueryable<CompReport>> OrderCompsForEmployeeIdByFrequencyQuery =
           CompiledQuery.Compile((DominicaEntities context, EmployeeCompInput inputs) =>
              (from S in context.SALES
               where S.FirstOrderedDateTime >= inputs.StartDate &&
              S.FirstOrderedDateTime <= inputs.EndDate &&
              S.UserId == inputs.EmployeeId &&
              S.DiscountId != null && S.ActualPrice != 0
               group S by S.DiscountId into occurrences
               join COMP_ACCOUNT in context.COMP_ACCOUNTS on occurrences.Key equals COMP_ACCOUNT.Id
               select
               new CompReport { Comp = COMP_ACCOUNT, Count = occurrences.Count(), CompPayments = occurrences }).OrderByDescending(p => p.Count).Take(inputs.Take));


        private static readonly Func<DominicaEntities,
           EmployeeCompInput, IQueryable<CompReport>> OrderCompsForAllEmployeeIdByFrequencyQuery =
           CompiledQuery.Compile((DominicaEntities context, EmployeeCompInput inputs) =>
              (from S in context.SALES.Include("ORDER")
               where S.FirstOrderedDateTime >= inputs.StartDate && S.ActualPrice != 0 &&
              S.FirstOrderedDateTime <= inputs.EndDate && S.DiscountId != null
               group S by S.DiscountId into occurrences
               join COMP_ACCOUNT in context.COMP_ACCOUNTS on occurrences.Key equals COMP_ACCOUNT.Id
               select
               new CompReport { Comp = COMP_ACCOUNT, Count = occurrences.Count(), CompPayments = occurrences })
               .OrderByDescending(p => p.Count).Take(inputs.Take));



        /// <summary>
        /// 
        /// </summary>
        private static readonly Func<DominicaEntities,
            CompExpenseReportInput, Decimal> GetExpenseForCompIdEmpId =
            CompiledQuery.Compile((DominicaEntities context, CompExpenseReportInput inputs) =>
                          (from S in context.SALES
                           where S.FirstOrderedDateTime >= inputs.StartDate &&
                           S.FirstOrderedDateTime <= inputs.EndDate &&
                           S.DiscountId == inputs.CompId &&
                           S.UserId == inputs.UserId
                           select (S.DiscountRate * S.ActualPrice)).Sum());

        /// <summary>
        /// 
        /// </summary>
        private static readonly Func<DominicaEntities,
            CompExpenseReportInput, Decimal> GetExpenseForCompIdAllEmpId =
            CompiledQuery.Compile((DominicaEntities context, CompExpenseReportInput inputs) =>
                          (from S in context.SALES
                           where S.FirstOrderedDateTime >= inputs.StartDate &&
                           S.FirstOrderedDateTime <= inputs.EndDate && S.ActualPrice != 0 &&
                           S.DiscountId == inputs.CompId
                           select (S.DiscountRate * S.ActualPrice)).Sum());

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dayCount"></param>
        /// <param name="employeeId"></param>
        /// <param name="cb"></param>
        public static void GetComps(int limitTo, DateTime startDate,
            DateTime endDate, Int64 employeeId, string userName, CompByEmployeeReportCallbackType cb)
        {
            try
            {
                List<CompReport> list = null;
                using (DominicaEntities context = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    context.TRANSACTIONS.MergeOption = MergeOption.NoTracking;

                    EmployeeCompInput inputs = new EmployeeCompInput();
                    inputs.StartDate = startDate;
                    inputs.EndDate = endDate;
                    inputs.Take = limitTo;
                    inputs.EmployeeId = employeeId;

                    if (employeeId == DominicaEntities.CONST_ALL_DB_OBJECTS_WILDCARD)
                    {
                        var q = OrderCompsForAllEmployeeIdByFrequencyQuery(context, inputs);

                        if (q != null && q.Any())
                        {
                            list = q.ToList();

                            CompExpenseReportInput payCompReport = new CompExpenseReportInput();
                            payCompReport.StartDate = inputs.StartDate;
                            payCompReport.EndDate = inputs.EndDate;
                            payCompReport.UserId = employeeId;

                            ///Get the total sales for each.
                            foreach (CompReport compReport in list)
                            {
                                compReport.UserName = userName;
                                payCompReport.CompId = compReport.Comp.Id;
                                compReport.Sales = GetExpenseForCompIdAllEmpId(context, payCompReport);
                            }
                            Oceanside.Constants.MainDispatcher.Invoke(cb, list);
                        }
                    }
                    else
                    {
                        var q = OrderCompsForEmployeeIdByFrequencyQuery(context, inputs);

                        if (q != null && q.Any())
                        {
                            list = q.ToList();

                            CompExpenseReportInput payCompReport = new CompExpenseReportInput();
                            payCompReport.StartDate = inputs.StartDate;
                            payCompReport.EndDate = inputs.EndDate;
                            payCompReport.UserId = employeeId;

                            ///Get the total sales for each.
                            List<CompReport> zerobalList = new List<CompReport>();
                            foreach (CompReport compReport in list)
                            {
                                compReport.UserName = userName;
                                payCompReport.CompId = compReport.Comp.Id;
                                compReport.Sales = GetExpenseForCompIdEmpId(context, payCompReport);
                                if (compReport.Sales == 0)
                                {
                                    zerobalList.Add(compReport);
                                }
                            }
                            foreach (CompReport cr in zerobalList)
                            {
                                list.Remove(cr);
                            }
                            Oceanside.Constants.MainDispatcher.Invoke(cb, list);
                        }
                    }

                }
                App.InvokeStopStoryBoard_NOTHROW();
            }
            catch (Exception e)
            {
                Oceanside.Constants.ErrorDispatcher.Notify(Oceanside.Error.EType.E_REPORT_ERROR, e);
            }
            finally
            {
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }
    }
}
